/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package horsechess.client.handle;

import horsechess.client.data.CustomizeData;
import horsechess.client.data.PlayerData;
import horsechess.client.gui.GUIClient;
import horsechess.client.gui.GUIOption;
import horsechess.packet.PlayerPacket;
import horsechess.server.data.ServerInfo;
import horsechess.util.Status;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Administrator
 */
public class PlayerConnect {

    private PlayerPacket packet;
    public ServerInfo infoServer = null;
    private Status status;
    private int port = 7777;
    // Which address
    private String group = "225.4.5.6";
    private String exception;
    // Create the socket and bind it to port 'port'.
    private BufferedReader in;
    private PrintWriter out;
    private Vector lstMessage;
    private GUIClient guiControl;
    private String room;
    private int second = 6;
    private Socket clientSocket;

    public PlayerConnect(GUIClient uIClient) {

        lstMessage = new Vector();
        this.guiControl = uIClient;


    }

    public Thread startReceiveServer() {
        Thread t = new Thread(new ServerReceive());
        t.start();
        return t;
    }

    public class ServerReceive implements Runnable {

        public void receiveServerInfo() {
            try {

                MulticastSocket s = new MulticastSocket(port);
                s.joinGroup(InetAddress.getByName(group));
                byte buf[] = new byte[1024];
                DatagramPacket pack = new DatagramPacket(buf, buf.length);
                s.receive(pack);
                System.out.println("Received data from: " + pack.getAddress().toString()
                        + ":" + pack.getPort() + " with length: "
                        + pack.getLength());

                String data = new String(pack.getData());
                System.out.println("Received data " + data.trim() + " ...from: " + pack.getAddress().getHostAddress()
                        + ":" + pack.getPort() + " with length: "
                        + pack.getLength());
                infoServer = new ServerInfo(pack.getAddress().getHostAddress(), Integer.parseInt(data.trim()));

                setStatus(Status.BEGIN_CONNECT);
                guiControl.customizeArgu.updateDisplay();
                guiControl.customizeArgu.btnConnect.setEnabled(true);
                Thread.currentThread().stop();
            } catch (IOException ex) {
                setStatus(Status.EXCEPTION);
                exception = "Cannot receive the server info. Please click get host again";
            }
        }

        public void run() {
            receiveServerInfo();
        }
    }

    public void makeConnection(String playerName) throws IOException {
        try {
            packet = new PlayerPacket(playerName, "Server A");
            //System.out.println("Make connection to server with address: " + infoServer.serverAddress + " port: " + infoServer.port);
            clientSocket = new Socket(infoServer.serverAddress, infoServer.port);

            InputStreamReader streamReader = new InputStreamReader(clientSocket.getInputStream());
            in = new BufferedReader(streamReader);
            out = new PrintWriter(clientSocket.getOutputStream(), true);
            status = Status.CONNECTING;
            send(status.toString(Status.CONNECTING));
            Thread t = new Thread(new RemoteReader());
            guiControl.customizeArgu.lblMessage.setText("Receiving info from server");
            //System.out.println("zzz");
            t.start();
        } catch (IOException io) {
            status = Status.EXCEPTION;
            io.printStackTrace();
            exception = io.getMessage();
            clientSocket.close();
        }
    }

    public void joinTheRoom(String PlayerName, String roomName) {
        room = roomName;
        packet = new PlayerPacket(PlayerName, room);
        send(packet.room());
        status = Status.CONNECTING;
    }

    public void requireForDisconnect() {
        try {
            status = Status.DISCONNECTED;
            send(status.toString(Status.DISCONNECTED));
            clientSocket.close();
        } catch (IOException ex) {
            guiControl.customizeArgu.lblMessage.setText("Fail to disconnect with server");
        }
    }

    public void turnToPlayer(PlayerPacket currInfoPlayer, PlayerPacket nextPlayer) {
        send("@Other:" + currInfoPlayer.toString() + "#" + status.OTHER_TURN + ":" + nextPlayer.toString() + "#" + status.YOUR_TURN);

        status = Status.OTHER_TURN;
        handleStatus();
        // System.out.println("End of " + currInfoPlayer.getPlayerName() + " turn!!!");
    }

    public void sendCMPosition(PlayerPacket currInfoPlayer) {
        send("@Other:" + currInfoPlayer.toString() + "#" + status.OTHER_TURN);
    }

    public String getMessage() {
        switch (status) {
            case BEGIN_CONNECT:
                return getName() + " can make the connection with server.";
            case CONNECTING:
                return getName() + " connected to server at address " + infoServer.serverAddress;
            case CONNECTED:
                return getName() + " has joined the room " + room + " at server address: " + infoServer.serverAddress;
            case DISCONNECTED:
                return getName() + " has failed to connect with server at address " + infoServer.serverAddress;
            case DISCONNECTING:
                return getName() + " has been requiring the server for disconnect. Please wait for server disconnect with you.";
            case EXCEPTION:
                return "There was error occured at client: " + exception + " !!!!";
            default:
                return "There was error occured at client!!";
        }
    }

    public void send(String message) {
        out.println(message);
        //System.out.println(message);
    }

    public String getName() {
        try {
            if (packet.getPlayerName() == null) {
                return "User";
            }
        } catch (NullPointerException ex) {
            return "User";
        }
        return packet.getPlayerName();
    }

    public void setName(String playerName) {
        packet.setPlayerName(playerName);
    }

    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    public ServerInfo getInfoServer() {
        return infoServer;
    }

    public void setInfoServer(ServerInfo infoServer) {
        this.infoServer = infoServer;
    }

    public class RemoteReader implements Runnable {

        String message = null;

        public void run() {
            try {
                while ((message = in.readLine()) != null) {
                    ///  System.out.println("Got an message from server: " + message);
                    if (message.contains("#")) {
                        processMessage(message);
                    } else if (message.contains("-")) {
                        String[] rooms = message.split("-");
                        //System.out.println("Ngu qua @@@: " + rooms[0]);
                        if (rooms[0].equalsIgnoreCase("@Room")) {
                            //  System.out.println("Ngu qua @@@");
                            infoServer.setRoom(message);
                            guiControl.customizeArgu.updateRooms();
                        }
                    } else {
                        handleGameOver(message);
                    }
                }
            } catch (SocketException e) {
                serverShutdown();
            } catch (Exception e) {
                e.printStackTrace();
                status = Status.EXCEPTION;
                exception = e.getMessage();
            }
        }
    }

    private void handleGameOver(String message) {
        if (message.equalsIgnoreCase("@GAME_OVER")) {
            guiControl.gameOver();
        }
    }

    private void serverShutdown() {
        status = Status.EXCEPTION;
        guiControl.customizeArgu.lblMessage.setText("Failed to make the connection with server");
        //guiControl.resetInterface();
        guiControl.customizeArgu.disconnect();
        guiControl.dispose();
    }

    public void handleStatus() {
        switch (status) {
            case START_GAME:
                guiControl.lblMessage.setText("Game started!!");
                guiControl.startGame();
                break;
            case OTHER_TURN:
                guiControl.lblEndingMessage.setText("Other turn!!!");
                guiControl.lblMessage.setText("Please wait for other player to play!!!");
                guiControl.btnRollingDice.setEnabled(false);
                break;
            case GAMEOVER:
                guiControl.gameOver();
                break;
            case SHUT_DOWN:
                serverShutdown();
                break;
            case EXCEPTION:
                guiControl.customizeArgu.lblMessage.setText(getMessage());
                break;

        }
    }

    public void rollDice() {
        send("@RollDice#" + guiControl.customizeArgu.cData.getNumberOfDice());
    }

    public void position(String player, int horse) {
        send("@HorseMove#" + player + "#" + horse);
    }

    public void processMessage(String message) {
        String[] strs = message.split("#");

        //Message
        if (strs[0].equals("@Chat")) {
            synchronized (lstMessage) {
                lstMessage.add(strs[1]);
                GUIClient.customizeArgu.incommingList.setListData(lstMessage);
            }
        }
        if (strs[0].equals("@RollDice")) {
            //2 Xi ngau
            if (strs.length == 3) {
                guiControl.processTurn(Integer.parseInt(strs[1]), Integer.parseInt(strs[2]));
            }
        }
        if (strs[0].equals("@Player")) {
            try {
                //System.out.println("Set info message: " + message);
                PlayerPacket player = new PlayerPacket(message);

                try {
                    if (strs[8] != null) {
                        if (strs[8].equals(status.DISCONNECTED.toString())) {
                            //System.out.println(player.getPlayerName() + " have been disconnected!!!");
                            guiControl.disconnectedPlayer(player.getPlayerName());
                            //guiControl.customizeArgu.disconnect();
                            //guiControl.dispose();
                        }
                        if (strs[8].equals("SHUT_DOWN")) {
                            status = Status.EXCEPTION;
                            guiControl.customizeArgu.lblMessage.setText("Failed to make the connection with server");
                            //guiControl.resetInterface();
                            guiControl.customizeArgu.disconnect();
                            guiControl.dispose();
                            Thread.currentThread().stop();
                        }
                    }
                } catch (Exception e) {
                }

                switch (status) {
                    case CONNECTED:
                        //System.out.println("Test");
                        guiControl.customizeArgu.lblMessage.setText(player.getPlayerName() + " has been connected with system.");
                        guiControl.customizeArgu.updatePlayerInfo(player);
                        CustomizeData cData = GUIClient.customizeArgu.cData;
                        cData.setPlayerNames(player.getPosOfPlayer(), player.getPlayerName());
                        // System.out.println(cData.playerNames[player.getPosOfPlayer()]);
                        cData.numberChessMan[player.getPosOfPlayer()] = player.getNumberOfChessman();
                        GUIClient.customizeArgu.cData = cData;
                        break;
                }



            } catch (Exception e) {
                status = Status.EXCEPTION;
                e.printStackTrace();
                exception = "Cannot received infomration of player: " + e.getMessage();
            }
        }
        if (strs[0].equals("@Status")) {
            // System.out.println("Set status");
            if (strs[1].equalsIgnoreCase("CONNECTED")) {
                status = Status.CONNECTED;
                guiControl.customizeArgu.clearPlayer();
            }
            if (strs[1].equalsIgnoreCase("START_GAME")) {
                status = Status.START_GAME;
                if (guiControl.mniChat == null) {
                    // System.out.println("Null roi` ba con oi@@@@@!!!!");
                }
                guiControl.mniChat.setEnabled(true);
                guiControl.customizeArgu.setVisible(false);
                guiControl.setLocation(0, 0);
                guiControl.startGame();
            }
            if (strs[1].equalsIgnoreCase("LOSE")) {
                status = Status.LOSE;
            }
            if (strs[1].equalsIgnoreCase("DISCONNECTED")) {
                status = Status.DISCONNECTED;
            }
            if (strs[1].equalsIgnoreCase("SHUT_DOWN")) {
                status = Status.SHUT_DOWN;
            }
            handleStatus();
        }

        if (strs[0].equals("@Dice")) {
            //System.out.println("Number Of Dice: "+ Integer.parseInt(strs[1]));
            guiControl.customizeArgu.cData.setNumberOfDice(Integer.parseInt(strs[1]));

            guiControl.customizeArgu.setDice();
            guiControl.cb.updateDataChessBoard(GUIClient.customizeArgu.cData);
        }
        if (strs[0].equals("@Priority")) {
            int priority = Integer.parseInt(strs[1]);
            GUIClient.customizeArgu.cData.setPriorityPerson(priority);
            GUIClient.customizeArgu.updatePriorityPerson();
        }
        if (strs[0].equals("@NoOfPlayer")) {
            int noOfPlayer = Integer.parseInt(strs[1]);
            GUIOption.txtOptionPlayer.setText(noOfPlayer + "");
            GUIClient.customizeArgu.cData.setNumberOfPlayer(noOfPlayer);
        }
        if (strs[0].equalsIgnoreCase("@HorseMove")) {
            guiControl.updateMoving(strs[1], Integer.parseInt(strs[2]));
        }
        if (strs[0].equalsIgnoreCase("@Clock")) {
            guiControl.updateTime(strs[1]);
        }
        if (strs[0].equalsIgnoreCase("@Turn")) {
            guiControl.updateTurn(Integer.parseInt(strs[1]));
        }
        if (strs[0].equalsIgnoreCase("@Lose")) {
            PlayerData losePlayer = guiControl.cb.getInformationBoard().players.get(Integer.parseInt(strs[2]));
            guiControl.lose(losePlayer);
        }
        if (strs[0].equalsIgnoreCase("@Won")) {
            PlayerData wonPlayer = guiControl.cb.getInformationBoard().players.get(Integer.parseInt(strs[2]));
            guiControl.win(wonPlayer, true);
        }

        if (strs[0].equalsIgnoreCase("@Disconnected")) {
            guiControl.disconnectedPlayer(strs[1]);
        }
        if (strs[0].equalsIgnoreCase("@MatchTime")) {
            if (strs[1].trim().equalsIgnoreCase("Timeout!!")) {
                guiControl.calculateHighgestPlayer();
            }
            guiControl.lblTimeOfMatch.setText(strs[1]);
        }
    }

    public void controlClock(int control) {
        switch (control) {
            case 2:
                send("@Clock#Stop");
                break;
            case 3:
                send("@Clock#Restart");
                break;
            default:
                send("@Clock#Stop");
                break;
        }
    }

    public void turnTo(int nxtPlayer) {
        send("@Turn#" + nxtPlayer);
    }
}
